/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __GPK_ARCHIVE_H__
#define __GPK_ARCHIVE_H__

#include "EnginePrerequisites.h"
#include "GPKFile.h"

namespace PQEngine
{

	/*GPK archive(virtual file system) used by engine.
	@Note:
	remove file was not permit for simplicity.
	(remove last file is ok,but other case need copy many file data)
	maybe we should develop a archive format that have 512KB chunks,
	file size represented as chunks + last chunk bytes
	*/
	class GPKArchive
	{
	public:
		friend int GPKFile::read(char* buf,int size);//allow this to access our protected functions

		static const std::string MAGIC;
		static const std::string EXT_GPK;
		static const std::string EXT_META;//assit for search file use names

		typedef std::map<std::string,GPKArchive*> ArchiveMap;
		typedef std::vector<GPKFile*> GPKFileVector;
		
	protected:
		/*Build game should use,but run game may not need useAssistFile
		*/
		GPKArchive(std::string path,bool useAssistFile=true);
	public:
		~GPKArchive();
		/*Path should be full path on local file system.
		Note:create when not exist
		*/
		static GPKArchive* get(std::string path);

		/*Add local file at filePath to archive.
		Return false if fileName already exist.
		Note: this function used for game builder not game player.
		@param filePath - the file path on local file system
		*/
		bool addFile(std::string filePath);
		
		inline int getNumFile()
		{
			return _header.numFile;
		}

		inline std::string getFileName(int index)
		{
			assert(index>=0&&index<_fileNames.size());
			return _fileNames[index];
		}

		/*Get file in .gpk file id,now only the index of file array.
		@param fileName- eg(*.mesh,folder/folder/*.mesh)
		*/
		int getFileIndex(std::string fileName);
		
		/*Get index-th file in archive.
		*/
		GPKFile* getFile(int index);

		/*Get file in archive with in archive name.
		*/
		GPKFile* getFile(std::string fileName);
		bool hasFile(std::string fileName);

		/*Check whether the file exist
		*/
		bool isFileExist(std::string fileName);

	protected:
		/*Read file data
		@Param offset - the bytes already read in file.
		*/
		void readFileData(int id,int offset,char* buf,int size);

	private:
		void initGPKFiles();
		/*Get available index range from 0 to 4095
		*/
		int getGPKFreeSlot();

		void persistMetaFile();
	private:
		static ArchiveMap _map;
		//std::fstream _fstream;//assiciate with .gpk file

		GPKHeader _header;//search gpk info
		GPKFile _files[GPACK_FILE_LIMIT];//gpk file array

		bool _useAssistFile;

		std::string _path;//file name is full path of the file in local file system
		std::string _assitFilePath;//assist file in local file system

		StringVector _fileNames;//file names in .gpk
		
	};
}
#endif


